using System.Linq;
using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Serial;

namespace HslCommunication.Profinet.Omron
{
	/// <summary>
	/// 欧姆龙的HostLink协议的实现，地址支持示例 DM区:D100; CIO区:C100; Work区:W100; Holding区:H100; Auxiliary区: A100<br />
	/// Implementation of Omron's HostLink protocol, address support example DM area: D100; CIO area: C100; Work area: W100; Holding area: H100; Auxiliary area: A100
	/// </summary>
	/// <remarks>
	/// <inheritdoc cref="T:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp" path="remarks" />
	/// </remarks>
	public class OmronHostLink : SerialDeviceBase
	{
		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp.ICF" />
		public byte ICF
		{
			get;
			set;
		} = 0;


		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp.DA2" />
		public byte DA2
		{
			get;
			set;
		} = 0;


		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp.SA2" />
		public byte SA2
		{
			get;
			set;
		}

		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp.SID" />
		public byte SID
		{
			get;
			set;
		} = 0;


		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp.ResponseWaitTime" />
		public byte ResponseWaitTime
		{
			get;
			set;
		} = 48;


		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronHostLinkOverTcp.UnitNumber" />
		public byte UnitNumber
		{
			get;
			set;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.#ctor" />
		public OmronHostLink()
		{
			base.ByteTransform = new ReverseWordTransform();
			base.WordLength = 1;
			base.ByteTransform.DataFormat = DataFormat.CDAB;
			base.ByteTransform.IsStringReverseByteWord = true;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Read(System.String,System.UInt16)" />
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildReadCommand(address, length, isBit: false);
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult<byte[]> operateResult2 = ReadBase(PackCommand(operateResult.Content));
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult2);
			}
			OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, isRead: true);
			if (!operateResult3.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult3);
			}
			return OperateResult.CreateSuccessResult(operateResult3.Content);
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Write(System.String,System.Byte[])" />
		public override OperateResult Write(string address, byte[] value)
		{
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildWriteWordCommand(address, value, isBit: false);
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult<byte[]> operateResult2 = ReadBase(PackCommand(operateResult.Content));
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, isRead: false);
			if (!operateResult3.IsSuccess)
			{
				return operateResult3;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.ReadBool(System.String,System.UInt16)" />
		public override OperateResult<bool[]> ReadBool(string address, ushort length)
		{
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildReadCommand(address, length, isBit: true);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult);
			}
			OperateResult<byte[]> operateResult2 = ReadBase(PackCommand(operateResult.Content));
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult2);
			}
			OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, isRead: true);
			if (!operateResult3.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult3);
			}
			return OperateResult.CreateSuccessResult(operateResult3.Content.Select((byte m) => (m != 0) ? true : false).ToArray());
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Write(System.String,System.Boolean[])" />
		public override OperateResult Write(string address, bool[] values)
		{
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildWriteWordCommand(address, values.Select((bool m) => (byte)(m ? 1 : 0)).ToArray(), isBit: true);
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult<byte[]> operateResult2 = ReadBase(PackCommand(operateResult.Content));
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, isRead: false);
			if (!operateResult3.IsSuccess)
			{
				return operateResult3;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return $"OmronHostLink[{base.PortName}:{base.BaudRate}]";
		}

		/// <summary>
		/// 将普通的指令打包成完整的指令
		/// </summary>
		/// <param name="cmd">fins指令</param>
		/// <returns>完整的质量</returns>
		private byte[] PackCommand(byte[] cmd)
		{
			cmd = SoftBasic.BytesToAsciiBytes(cmd);
			byte[] array = new byte[18 + cmd.Length];
			array[0] = 64;
			array[1] = SoftBasic.BuildAsciiBytesFrom(UnitNumber)[0];
			array[2] = SoftBasic.BuildAsciiBytesFrom(UnitNumber)[1];
			array[3] = 70;
			array[4] = 65;
			array[5] = ResponseWaitTime;
			array[6] = SoftBasic.BuildAsciiBytesFrom(ICF)[0];
			array[7] = SoftBasic.BuildAsciiBytesFrom(ICF)[1];
			array[8] = SoftBasic.BuildAsciiBytesFrom(DA2)[0];
			array[9] = SoftBasic.BuildAsciiBytesFrom(DA2)[1];
			array[10] = SoftBasic.BuildAsciiBytesFrom(SA2)[0];
			array[11] = SoftBasic.BuildAsciiBytesFrom(SA2)[1];
			array[12] = SoftBasic.BuildAsciiBytesFrom(SID)[0];
			array[13] = SoftBasic.BuildAsciiBytesFrom(SID)[1];
			array[array.Length - 2] = 42;
			array[array.Length - 1] = 13;
			cmd.CopyTo(array, 14);
			int num = array[0];
			for (int i = 1; i < array.Length - 4; i++)
			{
				num ^= array[i];
			}
			array[array.Length - 4] = SoftBasic.BuildAsciiBytesFrom((byte)num)[0];
			array[array.Length - 3] = SoftBasic.BuildAsciiBytesFrom((byte)num)[1];
			return array;
		}
	}
}
